Computer programs developed by program developers are oftentimes relatively large and complex. For instance, source code of an operating system can include hundreds of thousands to millions of lines of code, wherein different portions of the code are written by different developers over varying time frames. Because developers are often unable to surmise all possible executions through source code, unforeseen errors can occur at runtime of a program. For example, certain variable values, events, execution paths, some combination thereof, etc. may cause the program to operate in an unexpected/undesirable manner when executed (e.g., the program includes potential bugs). To detect bugs, static analysis and verification tools have been developed.
A static analysis and verification tool analyzes computer-executable code to identify potential bugs that may occur during program execution, such as null pointer exceptions, division by zero errors, array out of bounds errors, and the like. In certain instances, a developer provided with warnings may wish to ignore such warnings, as the bugs may be spurious or not worth fixing (e.g., fixing a bug may cause more severe problems in the program). Going forward, then, the developer may wish to have these “old” warnings suppressed, as the developer has already reviewed the warnings, and re-provision of the same warnings is superfluous. In other words, suppressing warnings may allow the developer to be notified only of issues caused by the addition of new features to the program.
Using conventional static analysis and verification tools, the options of the developer are either to 1) add assume statements to the code to suppress each undesired warning; or 2) suppress warnings via attributes or alarm filter files. These approaches have numerous drawbacks. For instance, the first option allows the developer to make assumptions explicit, but this is only an advantage if such assumptions are interesting to the developer. Moreover, inserting assumptions requires manual effort proportional to the number of warnings emitted by the tool that are desirably suppressed by the developer. Still further, the developer must manually refactor any assumptions as changes to the program are made. With respect to the second option noted above, warnings can be suppressed by way of syntactic matches between warning messages, warning types, or warning locations. Thus, for instance, the developer can indicate that any warnings at line i of a program is to be suppressed when new versions of the program are analyzed.
With more generality, the developer can add a suppression attribute (or an entry in an alarm filter file) after manual inspection of a warning; such syntax-based suppressions, however, can be quite brittle, in that small changes to a program can cause syntactic matching to fail. Failed suppression can then cause alarms to be re-reported that have already been classified as spurious by the developer, thereby causing confusion and irritation. Further, using syntactic matching may unintentionally suppress warnings that are, in fact, genuinely new (e.g., caused by a revision to a program). For instance, a line-based suppression strategy may desirably suppress all warnings about an assertion failure at line i of a program. Accordingly, a warning based on an assertion a0 at line i may be suppressed in an original program. If, however, the developer inserts a new and potentially failing assertion a1 at line i in the program, thereby shifting a0 back to line i+1, the warning about the failure of a1 will be (wrongly) suppressed, and the warning about the failure of a0 will be (wrongly) reported.